/*
在代码量较大的情况下,为了避免命名空间冲突,可以将相似的函数、类、接口放置到命名空间内
命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象,命名空间内通过export向外导出
命名空间是内部模块,主要用于组织代码,避免命名冲突

命名空间相当于就是一个闭包
只不过我们访问闭包里的成员不是通过闭包的返回
而是通过内部的成员主动向外暴露(export)
并且我们访问这些个成员时还需要带上命名空间的名字

在组织方面，命名空间对于在全局作用域内对逻辑上相关的对象和类型进行分组是很便利的
但模块里不要使用命名空间  模块具有其自己的作用域，并且只有导出的声明才会在模块外部可见。 记住这点，命名空间在使用模块时几乎没什么价值。
比如下面↓就是在模块里(export)导出命名空间 其实没有必要
*/

export namespace zoo {
  export class Dog { eat() { console.log('zoo dog'); } }

  const x = 1; // 外部不能访问

  export function consoleX() {
    console.log(x); // 外部可以这样访问到
  }
}
//↑ 一个namespace其实就是一个自执行函数
/*
var zoo;
(function(){
  zoo.Dog = class Dog
  ...
})(zoo || (zoo = {}))
*/

namespace home {
  export class Dog { eat() { console.log('home dog'); } }
}

const dog_of_zoo = new zoo.Dog();
dog_of_zoo.eat(); // zoo dog

const dog_of_home = new home.Dog();
dog_of_home.eat(); // home dog

// console.log(zoo.x); //TS2339: Property 'x' does not exist on type 'typeof zoo'.

zoo.consoleX(); // 1


